package com.dm.library.widgets;

import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.dm.library.R;


/**
 * 版 权: 深圳市迪蒙网络科技有限公司
 * 描 述: 滑到底部，自动加载更多的RecyclerView
 * 注意：该控件的父控件，或者本身的visibility属性不能是GONE，否则不会走onCreateViewHolder()方法
 * 导致mFooterViewHolder始终为null
 * 修 改 人: sushuo
 * 修改时间: 2016-6-29
 */
public class DMRecyclerView extends RecyclerView {

    /**
     * RecyclerView的垂直滑动监听
     */
    public interface DMRecyclerViewScrollListener {
        /**
         * 垂直滑动监听事件
         *
         * @param recyclerView
         * @param x
         * @param y            垂直滑动距离
         */
        void onScrolled(RecyclerView recyclerView, int x, int y);
    }

    /**
     * item 类型
     */
    public final static int TYPE_NORMAL = 0;
    public final static int TYPE_HEADER = 1;// 头部--支持头部增加一个headerView
    public final static int TYPE_FOOTER = 2;// 底部--往往是loading_more
    public final static int TYPE_LIST = 3;// 代表item展示的模式是list模式
    public final static int TYPE_STAGGER = 4;// 代码item展示模式是网格模式

    private boolean mIsFooterEnable = false;// 是否允许加载更多

    /**
     * 数据为空时的展示文字
     */
    private String emptyText = "暂无更多数据";

    /**
     * 自定义实现了头部和底部加载更多的adapter
     */
    private AutoLoadAdapter mAutoLoadAdapter;
    /**
     * 标记是否正在加载更多，防止再次调用加载更多接口
     */
    private boolean mIsLoadingMore;
    /**
     * 标记加载更多的position
     */
    private int mLoadMorePosition;
    /**
     * 加载更多的监听-业务需要实现加载数据
     */
    private LoadMoreListener mListener;

    private AutoLoadAdapter.FooterViewHolder mFooterViewHolder;

    /**
     * 是否有更多的数据
     */
    private boolean hasMoreData;


    /**
     * 保存上一次点击时间
     */
    private SparseArray<Long> lastClickTimes;

    private DMRecyclerViewScrollListener dmRecyclerViewScrollListener;

    public DMRecyclerView(Context context) {
        super(context);
        init();
    }

    public DMRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public DMRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    /**
     * 初始化-添加滚动监听
     * <p/>
     * 回调加载更多方法，前提是
     * <pre>
     *    1、有监听并且支持加载更多：null != mListener && mIsFooterEnable
     *    2、目前没有在加载，正在上拉（dy>0），当前最后一条可见的view是否是当前数据列表的最好一条--及加载更多
     * </pre>
     */
    private void init() {
        lastClickTimes = new SparseArray<Long>();
        super.addOnScrollListener(new OnScrollListener() {

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (dmRecyclerViewScrollListener != null) {
                    dmRecyclerViewScrollListener.onScrolled(recyclerView, 0, getScollYDistance());
                }
                if (null != mListener && mIsFooterEnable && !mIsLoadingMore && dy > 0) {
                    int lastVisiblePosition = getLastVisiblePosition();
                    if (lastVisiblePosition + 1 == mAutoLoadAdapter.getItemCount()) {
                        setLoadingMore(true);
                        mLoadMorePosition = lastVisiblePosition;

                        // 有更多数据才去加载更多 -- 只能在此判断，否则不会出现加载view
                        if (hasMoreData) {
                            mListener.onLoadMore();
                        }
                    }
                }
            }
        });
    }

    /**
     * 获取垂直方向滑动距离，注意：只适合LayoutManager用的是LinearLayoutManager
     *
     * @return
     */
    public int getScollYDistance() {
        LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();
        int position = layoutManager.findFirstVisibleItemPosition();
        View firstVisiableChildView = layoutManager.findViewByPosition(position);
        int itemHeight = firstVisiableChildView.getHeight();
        return (position) * itemHeight - firstVisiableChildView.getTop();
    }

    public void setDMRecyclerViewScrollListener(DMRecyclerViewScrollListener dmRecyclerViewScrollListener) {
        this.dmRecyclerViewScrollListener = dmRecyclerViewScrollListener;
    }

    /**
     * 设置加载更多的监听
     *
     * @param listener
     */
    public void setLoadMoreListener(LoadMoreListener listener) {
        mListener = listener;
    }

    /**
     * 设置正在加载更多
     *
     * @param loadingMore
     */
    public void setLoadingMore(boolean loadingMore) {
        this.mIsLoadingMore = loadingMore;
    }

    /**
     * 加载更多监听
     */
    public interface LoadMoreListener {
        /**
         * 加载更多
         */
        void onLoadMore();
    }

    /**
     *
     */
    public class AutoLoadAdapter extends Adapter<ViewHolder> {

        /**
         * 数据adapter
         */
        private Adapter mInternalAdapter;

        private boolean mIsHeaderEnable;
        private int mHeaderResId;
        private View mHeaderView;
        private int headerCount;

        public AutoLoadAdapter(Adapter adapter) {
            mInternalAdapter = adapter;
            mIsHeaderEnable = false;
        }

        @Override
        public int getItemViewType(int position) {
            int headerPosition = 0;
            int footerPosition = getItemCount() - 1;

            if (headerPosition == position && mIsHeaderEnable && (mHeaderResId > 0 || mHeaderView != null)) {
                return TYPE_HEADER;
            }
            if (footerPosition == position && mIsFooterEnable) {
                return TYPE_FOOTER;
            }
            /**
             * 这么做保证layoutManager切换之后能及时的刷新上对的布局
             */
            if (getLayoutManager() instanceof LinearLayoutManager) {
                return TYPE_LIST;
            } else if (getLayoutManager() instanceof StaggeredGridLayoutManager) {
                return TYPE_STAGGER;
            } else {
                return TYPE_NORMAL;
            }
        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == TYPE_HEADER) {
                if (mHeaderView != null) {
                    return new HeaderViewHolder(mHeaderView);
                } else if (mHeaderResId > 0) {
                    return new HeaderViewHolder(LayoutInflater.from(parent.getContext()).inflate(
                            mHeaderResId, parent, false));
                }
            }
            if (viewType == TYPE_FOOTER) {
                if (mFooterViewHolder == null) {
                    mFooterViewHolder = new FooterViewHolder(
                            LayoutInflater.from(parent.getContext()).inflate(
                                    R.layout.pulldown_footer, parent, false));
                }
                return mFooterViewHolder;
            } else {
                // type normal
                return mInternalAdapter.onCreateViewHolder(parent, viewType);
            }
        }

        public class FooterViewHolder extends ViewHolder {

            private View view;
            private TextView mFooterTextView;
            private View mFooterProgressLL;

            public FooterViewHolder(View itemView) {
                super(itemView);
                this.view = itemView;
                mFooterTextView = (TextView) view.findViewById(R.id.pulldown_footer_text);
                mFooterProgressLL = view.findViewById(R.id.footer_loading_progress_ll);
//                AnimationDrawable ad = (AnimationDrawable) getResources().getDrawable(R.drawable.loading_progress_round);
//                view.findViewById(R.id.imageView).setBackgroundDrawable(ad);
//                ad.start();
            }

            public View getFooterView() {
                return view;
            }

            public TextView getFooterTextView() {
                return mFooterTextView;
            }

            public View getFooterLoadingProgressLl() {
                return mFooterProgressLL;
            }

        }

        public class HeaderViewHolder extends ViewHolder {
            public HeaderViewHolder(View itemView) {
                super(itemView);
            }
        }

        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            int type = getItemViewType(position);
            if (type != TYPE_FOOTER && type != TYPE_HEADER) {
                if (mIsHeaderEnable && headerCount > 0) {
                    position = position - 1;
                }
                mInternalAdapter.onBindViewHolder(holder, position);
            }
        }

        /**
         * 需要计算上加载更多和添加的头部俩个
         *
         * @return
         */
        @Override
        public int getItemCount() {
            int count = mInternalAdapter.getItemCount();
            if (mIsFooterEnable) count++;
            if (mIsHeaderEnable) count++;

            return count;
        }

        public void setHeaderEnable(boolean enable) {
            mIsHeaderEnable = enable;
        }

        public void addHeaderView(int resId) {
            mHeaderResId = resId;
            headerCount++;
        }

        public void addHeaderView(View view) {
            mHeaderView = view;
            headerCount++;
        }
    }

    @Override
    public void setAdapter(Adapter adapter) {
        if (adapter != null) {
            mAutoLoadAdapter = new AutoLoadAdapter(adapter);
        }
        super.swapAdapter(mAutoLoadAdapter, true);

    }

    /**
     * 切换layoutManager（还有问题）
     * <p/>
     * 为了保证切换之后页面上还是停留在当前展示的位置，记录下切换之前的第一条展示位置，切换完成之后滚动到该位置
     * 另外切换之后必须要重新刷新下当前已经缓存的itemView，否则会出现布局错乱（俩种模式下的item布局不同），
     * RecyclerView提供了swapAdapter来进行切换adapter并清理老的itemView cache
     *
     * @param layoutManager
     */
    public void switchLayoutManager(LayoutManager layoutManager) {
        int firstVisiblePosition = getFirstVisiblePosition();
//        getLayoutManager().removeAllViews();
        setLayoutManager(layoutManager);
        //super.swapAdapter(mAutoLoadAdapter, true);
        getLayoutManager().scrollToPosition(firstVisiblePosition);
    }

    /**
     * 获取第一条展示的位置
     *
     * @return
     */
    private int getFirstVisiblePosition() {
        int position;
        if (getLayoutManager() instanceof LinearLayoutManager) {
            position = ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition();
        } else if (getLayoutManager() instanceof GridLayoutManager) {
            position = ((GridLayoutManager) getLayoutManager()).findFirstVisibleItemPosition();
        } else if (getLayoutManager() instanceof StaggeredGridLayoutManager) {
            StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) getLayoutManager();
            int[] lastPositions = layoutManager.findFirstVisibleItemPositions(new int[layoutManager.getSpanCount()]);
            position = getMinPositions(lastPositions);
        } else {
            position = 0;
        }
        return position;
    }

    /**
     * 获得当前展示最小的position
     *
     * @param positions
     * @return
     */
    private int getMinPositions(int[] positions) {
        int size = positions.length;
        int minPosition = Integer.MAX_VALUE;
        for (int i = 0; i < size; i++) {
            minPosition = Math.min(minPosition, positions[i]);
        }
        return minPosition;
    }

    /**
     * 获取最后一条展示的位置
     *
     * @return
     */
    private int getLastVisiblePosition() {
        int position;
        if (getLayoutManager() instanceof LinearLayoutManager) {
            position = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition();
        } else if (getLayoutManager() instanceof GridLayoutManager) {
            position = ((GridLayoutManager) getLayoutManager()).findLastVisibleItemPosition();
        } else if (getLayoutManager() instanceof StaggeredGridLayoutManager) {
            StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) getLayoutManager();
            int[] lastPositions = layoutManager.findLastVisibleItemPositions(new int[layoutManager.getSpanCount()]);
            position = getMaxPosition(lastPositions);
        } else {
            position = getLayoutManager().getItemCount() - 1;
        }
        return position;
    }

    /**
     * 获得最大的位置
     *
     * @param positions
     * @return
     */
    private int getMaxPosition(int[] positions) {
        int size = positions.length;
        int maxPosition = Integer.MIN_VALUE;
        for (int i = 0; i < size; i++) {
            maxPosition = Math.max(maxPosition, positions[i]);
        }
        return maxPosition;
    }

    /**
     * 添加头部view
     *
     * @param resId
     */
    public void addHeaderView(int resId) {
        mAutoLoadAdapter.addHeaderView(resId);
    }

    /**
     * 添加头部view
     *
     * @param view
     */
    public void addHeaderView(View view) {
        mAutoLoadAdapter.addHeaderView(view);
    }

    /**
     * 设置头部view是否展示
     *
     * @param enable
     */
    public void setHeaderEnable(boolean enable) {
        mAutoLoadAdapter.setHeaderEnable(enable);
    }

    /**
     * 设置是否展示自动加载更多
     *
     * @param enable
     */
    public void setAutoLoadMoreEnable(boolean enable) {
        mIsFooterEnable = enable;
    }

    /**
     * 此次加载更多数据的操作完毕，通知刷新view
     *
     * @param hasMoreData 是否有更多的数据待加载
     */
    public void notifyMoreFinish(boolean hasMoreData) {
//        setAutoLoadMoreEnable(hasMore);
//        getAdapter().notifyItemRemoved(mLoadMorePosition);

        this.hasMoreData = hasMoreData;
        setLoadingMore(false);
        refreshFooterView(hasMoreData);
        getAdapter().notifyDataSetChanged();
    }

    /**
     * 加载数据出错,点击再次加载
     */
    public void loadMoreError() {
        setLoadingMore(false);
        if (mFooterViewHolder != null) {
            mFooterViewHolder.getFooterView().setVisibility(View.VISIBLE);
            mFooterViewHolder.getFooterLoadingProgressLl().setVisibility(View.GONE);
            mFooterViewHolder.getFooterTextView().setVisibility(View.VISIBLE);
            mFooterViewHolder.getFooterTextView().setText("加载数据出错，点击重新加载~");
            mFooterViewHolder.getFooterView().setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (checkClick(view.getId())) {
                        if (mListener != null) {
                            refreshFooterView(hasMoreData);
                            mListener.onLoadMore();
                        }
                    }

                }
            });
        }
    }

    /**
     * 刷新底部加载view
     *
     * @param hasMoreData
     */
    private void refreshFooterView(boolean hasMoreData) {
        if (mFooterViewHolder != null) {
            if (hasMoreData) {
                mFooterViewHolder.getFooterView().setVisibility(View.VISIBLE);
                mFooterViewHolder.getFooterLoadingProgressLl().setVisibility(View.VISIBLE);
                mFooterViewHolder.getFooterTextView().setVisibility(View.GONE);
                mFooterViewHolder.getFooterTextView().setText("加载中");
            } else {
                mFooterViewHolder.getFooterView().setVisibility(View.VISIBLE);
                mFooterViewHolder.getFooterLoadingProgressLl().setVisibility(View.GONE);
                mFooterViewHolder.getFooterTextView().setVisibility(View.VISIBLE);
                mFooterViewHolder.getFooterTextView().setText("暂无更多数据");
            }
        }
    }

    /**
     * 空数据
     */
    public void hasEmptyData() {
        if (mFooterViewHolder != null) {
            mFooterViewHolder.getFooterView().setVisibility(View.VISIBLE);
            mFooterViewHolder.getFooterLoadingProgressLl().setVisibility(View.GONE);
            mFooterViewHolder.getFooterTextView().setVisibility(View.VISIBLE);
            mFooterViewHolder.getFooterTextView().setText(getEmptyText());
            getAdapter().notifyDataSetChanged();
        }
    }

    /**
     * 设置空数据时，底部view展示的文字提示
     *
     * @param emptyText
     */
    public void setEmptyText(String emptyText) {
        this.emptyText = emptyText;
    }

    /**
     * 获取空数据时，底部view展示的文字提示
     *
     * @return
     */
    public String getEmptyText() {
        return this.emptyText;
    }

    /**
     * 检查是否可执行点击操作 防重复点击
     *
     * @return 返回true则可执行
     */
    private boolean checkClick(int id) {
        Long lastTime = lastClickTimes.get(id);
        Long thisTime = System.currentTimeMillis();
        lastClickTimes.put(id, thisTime);
        return !(lastTime != null && thisTime - lastTime < 800);
    }

}
